package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.common.cache.GmallCache;
import com.atguigu.gmall.common.constans.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.model.product.*;
import com.atguigu.gmall.product.mapper.*;
import com.atguigu.gmall.product.service.ManageService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import net.bytebuddy.asm.Advice;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author 李旭
 * @date 2021/12/31 11:05
 * @Description:
 */
@Service
public class ManageServiceImpl implements ManageService {
    @Autowired
    private BaseCategory1Mapper baseCategory1Mapper;
    @Autowired
    private BaseCategory2Mapper baseCategory2Mapper;
    @Autowired
    private BaseCategory3Mapper baseCategory3Mapper;
    @Autowired
    private BaseAttrInfoMapper baseAttrInfoMapper;
    @Autowired
    private BaseAttrValueMapper baseAttrValueMapper;
    @Autowired
    private BaseTrademarkMapper baseTrademarkMapper;
    @Autowired
    private SpuInfoMapper spuInfoMapper;

    //查询一级分类的集合
    @Override
    public List<BaseCategory1> getCategory1() {
        return baseCategory1Mapper.selectList(null);
    }

    //获取二级分类
    @Override
    public List<BaseCategory2> getCategory2(Long category1Id) {
        return baseCategory2Mapper.selectList(new QueryWrapper<BaseCategory2>()
                .eq("category1_id", category1Id));
    }

    //获取三级分类
    @Override
    public List<BaseCategory3> getCategory3(Long category2Id) {
        return baseCategory3Mapper.selectList(new QueryWrapper<BaseCategory3>()
                .eq("category2_id", category2Id));
    }

    //根据分类id获取平台属性
    @Override
    public List<BaseAttrInfo> attrInfoList(Long category1Id, Long category2Id, Long category3Id) {
        //二表关联查询
        return baseAttrInfoMapper.attrInfoList(category1Id, category2Id, category3Id);
    }

    //添加
    @Override
    public void saveAttrInfo(BaseAttrInfo baseAttrInfo) {
        //1、保存平台属性  返回值
        baseAttrInfoMapper.insert(baseAttrInfo);
        //2:保存平台属性值
        List<BaseAttrValue> attrValueList = baseAttrInfo.getAttrValueList();
        if (!CollectionUtils.isEmpty(attrValueList)) {
            attrValueList.forEach(attrValue -> {
                //设置外键
                attrValue.setAttrId(baseAttrInfo.getId());
                baseAttrValueMapper.insert(attrValue);
            });
        }
    }

    //品牌分页查询
    @Override
    public IPage baseTrademark(Integer page, Integer limit) {
        return baseTrademarkMapper.selectPage(new Page<BaseTrademark>(page, limit), null);
    }

    //品牌添加
    @Override
    public void baseTrademarkSave(BaseTrademark baseTrademark) {
        baseTrademarkMapper.insert(baseTrademark);
    }

    //查询SPU 的分页结果集
    @Override
    public IPage spuPage(Integer page, Integer limit, Long category3Id) {
        return spuInfoMapper.selectPage(new Page<SpuInfo>(page, limit),
                new QueryWrapper<SpuInfo>().eq("category3_id", category3Id));
    }

    //添加SPU 之 品牌下拉框
    @Override
    public List<BaseTrademark> getTrademarkList() {
        return baseTrademarkMapper.selectList(null);
    }

    //添加SPU 之 销售属性下拉框
    @Override
    public List<BaseSaleAttr> baseSaleAttrList() {
        return baseSaleAttrMapper.selectList(null);
    }

    //SPU添加
    @Override
    public void saveSpuInfo(SpuInfo spuInfo) {
        //1:spu_info
        spuInfoMapper.insert(spuInfo);//
        //2:spu_image
        List<SpuImage> spuImageList = spuInfo.getSpuImageList();
        spuImageList.forEach(spuImage -> {
            //手写SQL  动态SQL <foreach>  Mybatis课程文档
            // insert into spu_image (id,...) values (),(),(),(),(),()  真批量
            spuImage.setSpuId(spuInfo.getId());
            spuImageMapper.insert(spuImage);
        });
        //3:spu_sale_attr
        List<SpuSaleAttr> spuSaleAttrList = spuInfo.getSpuSaleAttrList();
        spuSaleAttrList.forEach(spuSaleAttr -> {
            spuSaleAttr.setSpuId(spuInfo.getId());
            spuSaleAttrMapper.insert(spuSaleAttr);
            //4:spu_sale_attr_value
            List<SpuSaleAttrValue> spuSaleAttrValueList = spuSaleAttr.getSpuSaleAttrValueList();
            spuSaleAttrValueList.forEach(spuSaleAttrValue -> {
                spuSaleAttrValue.setSaleAttrName(spuSaleAttr.getSaleAttrName());
                spuSaleAttrValue.setSpuId(spuInfo.getId());
                spuSaleAttrValueMapper.insert(spuSaleAttrValue);
            });
        });
    }

    //根据SpuID查询所有此商品的图片  bigint
    @Override
    public List<SpuImage> spuImageList(Long spuId) {
        return spuImageMapper.selectList(new QueryWrapper<SpuImage>()
                .eq("spu_id", spuId));
    }

    //根据spuId获取销售属性
    @Override
    public List<SpuSaleAttr> spuSaleAttrList(Long spuId) {
        return spuSaleAttrMapper.spuSaleAttrList(spuId);
    }

    //保存SKU
    @Override
    public void saveSkuInfo(SkuInfo skuInfo) {
        //1:sku_info
        skuInfoMapper.insert(skuInfo);
        //2:sku_image
        List<SkuImage> skuImageList = skuInfo.getSkuImageList();
        skuImageList.forEach(skuImage -> {
            skuImage.setSkuId(skuInfo.getId());
            skuImageMapper.insert(skuImage);
        });

        //3:sku_SaleAttrValue
        skuInfo.getSkuSaleAttrValueList().forEach(skuSaleAttrValue -> {
            skuSaleAttrValue.setSkuId(skuInfo.getId());
            skuSaleAttrValue.setSpuId(skuInfo.getSpuId());
            skuSaleAttrValueMapper.insert(skuSaleAttrValue);
        });
        //4:sku_Attr_Value
        skuInfo.getSkuAttrValueList().forEach(skuAttrValue -> {
            skuAttrValue.setSkuId(skuInfo.getId());
            skuAttrValueMapper.insert(skuAttrValue);
        });
    }

    //查询SKU分页集合
    @Override
    public IPage skuPage(Integer page, Integer limit) {
        return skuInfoMapper.selectPage(new Page<SkuInfo>(page, limit), null);
    }

    @Autowired
    private RabbitService rabbitService;
    //上架
    @Override
    public void onSale(Long skuId) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setIsSale(SkuInfo.ISSALE);//上架   硬编码问题
        skuInfo.setId(skuId);
        //更新操作
        skuInfoMapper.updateById(skuInfo);
        //发消息 给ES索引库 进行添加索引
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_GOODS
         ,MqConst.ROUTING_GOODS_UPPER,skuId);

    }

    //下架
    @Override
    public void cancelSale(Long skuId) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setIsSale(SkuInfo.NOSALE);//上架
        skuInfo.setId(skuId);
        //更新操作
        skuInfoMapper.updateById(skuInfo);
        //要发消息 删除ES中的索引
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_GOODS
                ,MqConst.ROUTING_GOODS_LOWER,skuId);
    }

    //根据skuId查询sku_info  根据skuId查询sku_image  redissonClient
    @Override
    public SkuInfo getSkuInfo(Long skuId) {
        String cacheKey = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKUKEY_SUFFIX;
        //分布式锁的Key
        String cacheKeyLock = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKULOCK_SUFFIX;
        //1:先查询缓存  SkuInfo
        SkuInfo skuInfo = (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
        if (null == skuInfo) {
            //分布式锁 ：  解决：缓存的击穿问题
            RLock lock = redissonClient.getLock(cacheKeyLock);
         /*   RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(cacheKeyLock);
            readWriteLock.readLock().;
            readWriteLock.writeLock();*/
            //lock.lock(2,TimeUnit.SECONDS);//不见不散的锁
            //参数1：过期不候  过期的时间
            //参数2：锁的持有时间
            //参数3：单位
            try {
                boolean isLock = lock.tryLock(RedisConst.SKULOCK_EXPIRE_PX1,
                        RedisConst.SKULOCK_EXPIRE_PX2, TimeUnit.SECONDS);
                if (isLock) {
                    //获取到了锁
                    try {
                        //1.2:没有  查询DB 放到缓存中
                        skuInfo = skuInfoMapper.selectById(skuId);
                        //1.3:判断从DB中查询是否有数据
                        if (null != skuInfo) {
                            //1.3.1 : 有
                            //根据skuId查询sku_image
                            List<SkuImage> skuImageList = skuImageMapper.
                                    selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
                            skuInfo.setSkuImageList(skuImageList);
                            //放到缓存中  过期时间
                            redisTemplate.opsForValue().set(cacheKey, skuInfo, //解决缓存雪崩
                                    RedisConst.SKUKEY_TIMEOUT + new Random().nextInt(300)
                                    , TimeUnit.SECONDS);
                        } else {
                            //1.3.2: 没有  空结果  解决缓存的穿透问题
                            skuInfo = new SkuInfo();//对象中没有任何数据叫空结果
                            redisTemplate.opsForValue().set(cacheKey, skuInfo, 5, TimeUnit.MINUTES);
                        }
                    } finally {
                        //解锁
                        lock.unlock();
                    }
                }else{
                    //直接查询缓存
                    try {
                        TimeUnit.MILLISECONDS.sleep(500);
                        return (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return skuInfo;
    }

    //根据skuId查询sku_info  根据skuId查询sku_image
   /* @Override
    public SkuInfo getSkuInfo(Long skuId) {
        String cacheKey = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKUKEY_SUFFIX;
        //分布式锁的Key
        String cacheKeyLock = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKULOCK_SUFFIX;

                //1:先查询缓存  SkuInfo
        SkuInfo skuInfo = (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
        if(null == skuInfo) {

            //分布式锁 ：  解决：缓存的击穿问题
            String uuid = UUID.randomUUID().toString();
            Boolean isLock = redisTemplate.opsForValue().
                    setIfAbsent(cacheKeyLock, uuid, 2, TimeUnit.SECONDS);
            if(isLock){
                //获取到了锁
                try {
                    //1.2:没有  查询DB 放到缓存中
                    skuInfo = skuInfoMapper.selectById(skuId);
                    //1.3:判断从DB中查询是否有数据
                    if (null != skuInfo) {
                        //1.3.1 : 有
                        //根据skuId查询sku_image
                        List<SkuImage> skuImageList = skuImageMapper.
                                selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
                        skuInfo.setSkuImageList(skuImageList);
                        //放到缓存中  过期时间
                        redisTemplate.opsForValue().set(cacheKey, skuInfo, //解决缓存雪崩
                                RedisConst.SKUKEY_TIMEOUT + new Random().nextInt(300)
                                , TimeUnit.SECONDS);
                    } else {
                        //1.3.2: 没有  空结果  解决缓存的穿透问题
                        skuInfo = new SkuInfo();//对象中没有任何数据叫空结果
                        redisTemplate.opsForValue().set(cacheKey, skuInfo, 5, TimeUnit.MINUTES);
                    }
                } finally {
                    //解锁
                    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return tostring(redis.call('del',KEYS[1])) else return 0 end";
                    //执行上面的LUA脚本
                    this.redisTemplate.execute(new DefaultRedisScript<>(script),
                            Collections.singletonList(cacheKeyLock), uuid);
                }
            }else{
                //直接查询缓存
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                    return (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return skuInfo;
    }*/
    //查询实时价格
    @Override
    public BigDecimal getPrice(Long skuId) {
        // select price from sku_info where id = 1
        QueryWrapper queryWrapper = new QueryWrapper<SkuInfo>();
        queryWrapper.select("price").eq("id", skuId);
        SkuInfo skuInfo = skuInfoMapper.selectOne(queryWrapper);
        if (null != skuInfo) {
            return skuInfo.getPrice();
        }
        return null;
    }

    //根据category3Id查询一二三级分类
    @Override
    @GmallCache(prefix = "getBaseCategoryView:")
    public BaseCategoryView getBaseCategoryView(Long category3Id) {
        return baseCategoryViewMapper.selectById(category3Id);
    }

    //根据spuId查询spu_sale_attr_value(被选中项）  商品ID spu  库存ID
    @Override
    @GmallCache(prefix = "getSpuSaleAttrValue:")
    public List<SpuSaleAttr> getSpuSaleAttrValue(Long spuId, Long skuId) {
        List<SpuSaleAttr> spuSaleAttrListCheckBySku = spuSaleAttrMapper.getSpuSaleAttrListCheckBySku(skuId, spuId);
        if(CollectionUtils.isEmpty(spuSaleAttrListCheckBySku)){
            return null;
        }else{
            return spuSaleAttrListCheckBySku;
        }

    }

    //skuId与销售属性组合
    @Override
    @GmallCache(prefix = "spuValueIdsMap:")
    public Map spuValueIdsMap(Long spuId) {
        Map result = new HashMap();
        List<Map> skuValueIdsMap = skuSaleAttrValueMapper.getSkuValueIdsMap(spuId);
        skuValueIdsMap.forEach(map -> {
            result.put(map.get("value_ids"), map.get("sku_id"));
        });
        return result;
    }

    @Override
    public List<BaseCategoryView> getBaseCategoryViewList() {
        return baseCategoryViewMapper.selectList(null);
    }

    @Override
    public BaseTrademark getBaseTrademarkById(Long tmId) {
        return baseTrademarkMapper.selectById(tmId);
    }

    //根据skuId查询平台属性及属性值
    @Override
    public List<SkuAttrValue> getSkuAttrValueList(Long skuId) {
        return skuAttrValueMapper.getSkuAttrValueList(skuId);
    }

    @Autowired
    private BaseCategoryViewMapper baseCategoryViewMapper;
    @Autowired
    private BaseSaleAttrMapper baseSaleAttrMapper;
    @Autowired
    private SpuImageMapper spuImageMapper;
    @Autowired
    private SpuSaleAttrMapper spuSaleAttrMapper;
    @Autowired
    private SpuSaleAttrValueMapper spuSaleAttrValueMapper;
    @Autowired
    private SkuInfoMapper skuInfoMapper;
    @Autowired
    private SkuImageMapper skuImageMapper;
    @Autowired
    private SkuSaleAttrValueMapper skuSaleAttrValueMapper;
    @Autowired
    private SkuAttrValueMapper skuAttrValueMapper;
    @Autowired
    private RedisTemplate redisTemplate;//不是原生的RedisTemplate
    @Autowired
    private RedissonClient redissonClient;
}
